In   -
Out  main
Type AOF Debug
Ver  1.01g

{
        Simple main routine that calls an int main(int, char **) function
        Installs some simple handlers
        Assumes it is running in USR mode, ie as an app
}


#Area "JFP:Main:Code" Code ReadOnly
#Rem =Rem
#CodePrefix =Prefix
; ***************************************************************
; Name:         __main
; Function:     Set up stack and call _main
; On Entry:     nothing
; On Exit:      Exits via OS_Exit, setting return code
; Notes:        Globally exported
; ***************************************************************

>|__main| Entry
.aof_entryoffset
%aof_entryarea = aof_areas
        SWI     "OS_GetEnv"
        MOV     R13,R1                  ; set up the stack
        BL      _main                   ; call _main, the main workhorse
        ; _main returns in r0 the return code
        MOV     R2,R0                   ; put return code in r2
        LDR     R1,ABEX                 ; get abex
        ADR     R0,Errmes               ; absolutely no idea why we need an
                                        ; error buffer so gonna ignore it
        SWI     "OS_Exit"               ; and return control
.ABEX
        EQUS    "ABEX"                  ; should be in data segment but bah!

:

; ***************************************************************
; Name:         _main
; Function:     Set up error and exit handlers, and pass argc and v to main
; On Entry:     r0 -> *command
; On Exit:      r0 =  return value
; Notes:        Globally exported
; ***************************************************************


>|_main|
        STMFD   R13!,{R14}              ; preserve return address

        MOV     R5,R0                   ; keep hold of *command

        ADR     R3,Regblock
        ADR     R4,Handlers             ; point at Handlers

        MOV     R0,#1                   ; start at one
        ADR     R1,CrashHandler         ; crash handler address
        ADR     R2,Undefined
        BL      RegisterHandler

        MOV     R0,#2
        ADR     R2,Prefetch
        BL      RegisterHandler

        MOV     R0,#3
        ADR     R2,DataAbort
        BL      RegisterHandler

        MOV     R0,#4
        ADR     R2,AdrException
        BL      RegisterHandler

        MOV     R0,#11
        ADR     R1,ExitHandler
        BL      RegisterHandler

        ; now to work out argc and argv
        MOV     R0,R5
        BL      |strlen|                ; get length of *command
        ADD     R0,R0,#3+1              ; ADD +3 and zero term
        BIC     R0,R0,#3                ; word align

        MOV     R7,R13                  ; keep old stack pointer

        SUB     R13,R13,R0              ; claim enough memory to hold the
                                        ; *command
        MOV     R0,R13
        MOV     R1,R5
        BL      |strcpy|                ; copy the string into our writable
                                        ; area on the stack

        MOV     R5,R0                   ; point r5 at our copy now

        MOV     R1,#0                   ; set write address to 0
        BL      GetArgs                 ; get the args

        SUB     R13,R13,R0,LSL #2       ; get enough memory to store the **'s

        MOV     R0,R5                   ; get the *command
        MOV     R1,R13                  ; area to write the **'s
        BL      GetArgs                 ; and get the args

        ; r0 is number of args, **'s on stack
        MOV     R1,R13
        BL      |main|                  ; do the dirty work!

        MOV     R13,R7                  ; put stack pointer back

        BL      RemoveHandlers

        LDMFD   R13!,{PC}^

:

; ***************************************************************
; Name:         GetArgs
; Function:     Count args and fill in pointer to each arg
; On Entry:     r0 -> *command
;               r1 -> address of array of pointers, or 0
; On Exit:      r0 =  number of arguments
; Notes:        if r1 = 0, just count args, else put NULs on
;               end of each command and fill in buffer at r1
;               Sorts out quotes as well
; ***************************************************************
.GetArgs
        STMFD   R13!,{R1-R3,R14}
        MOV     R3,#0                   ; counter
$lp
        BL      |SkipWhitespace|
        LDRB    R2,[R0]                 ; get first character
        TEQ     R2,#0                   ; have we done?
        BEQ     $GotArgs                ; if so, tidy up and return

        ADD     R3,R3,#1                ; one more parameter

        TEQ     R2,#ASC""""             ; a quote?
        BEQ     $DealWithQuotes         ; then deal with 'em

        TEQ     R1,#0                   ; are we writing?
        STRNE   R0,[R1],#4              ; store address then

        BL      |SkipNonWhitespace|     ; skip to the end of this arg

        LDRB    R2,[R0]                 ; check that wasn't the end
        TEQ     R2,#0
        BEQ     $GotArgs                ; end

        TEQ     R1,#0                   ; are we writing?
        MOVNE   R14,#0
        STRNEB  R14,[R0]                ; blat a zero in to terminate the string
        ADD     R0,R0,#1                ; skip along a bit

        B       $lp

$DealWithQuotes
        ADD     R0,R0,#1                ; skip the quote
        TEQ     R1,#0                   ; writing?
        STRNE   R0,[R1],#4              ; write address past the quote
$FindMatchingQuote
        LDRB    R2,[R0]
        TEQ     R2,#0
        BEQ     $GotArgs                ; NUL matches the quote, and terminates
        TEQ     R2,#ASC""""             ; another quote?
        ADDNE   R0,R0,#1
        BNE     $FindMatchingQuote
; XXX MUST CHECK FOR ""s
        TEQ     R1,#0
        MOVNE   R2,#0
        STRNEB  R2,[R0]
        ADD     R0,R0,#1
        B       $lp

$GotArgs
        MOV     R0,R3                   ; return number of args
        LDMFD   R13!,{R1-R3,PC}^

:


; registers handler r0 with parms r1,r2,r3 storing old one at *r4
.RegisterHandler
        STMFD   R13!,{R1-R3,R14}
        SWI     "OS_ChangeEnvironment"
        STMIA   R4!,{R0-R3}
        LDMFD   R13!,{R1-R3,PC}^

; remove all handlers
.RemoveHandlers
        STMFD   R13!,{R0-R5,R14}
        ADR     R4,Handlers
        MOV     R5,#5
$lp
        LDMIA   R4!,{R0-R3}
        SWI     "XOS_ChangeEnvironment"
        SUBS    R5,R5,#1
        BNE     $lp
        LDMFD   R13!,{R0-R5,PC}^

:

.CrashHandler ; deals with all deaths - r12 points to string
        REMP    "*** FATAL ERROR ***"
        MOV     R0,R12
        SWI     "OS_WriteS"
        LDR     R0,Regblock + 15*4
        REMP    " at &$r0"
        BL      RemoveHandlers
        MOV     R0,R12
        LDR     R1,ABEX
        MVN     R2,#0
        SWI     "OS_Exit"

:

.ExitHandler
        BL      RemoveHandlers
        ADR     R0,Errmes
        LDR     R1,ABEX
        MVN     R2,#0
        SWI     "OS_Exit"

;---

#Area "JFP:Main:RWData" Data
.Regblock
        RES     16*4
.Handlers
        RES     (4*4*5)

#Area "JFP:Main:Data" Data ReadOnly
.Undefined
        EQUZA   "Undefined instruction"
.Prefetch
        EQUZA   "Prefetch abort"
.DataAbort
        EQUZA   "Data abort"
.AdrException
        EQUZA   "Address exception"
.Errmes
        EQUD    0
        EQUZA   ""